// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Diagnostics;

using Microsoft.TeamFoundation.Migration.Toolkit.Linking;

namespace Microsoft.TeamFoundation.Migration.Toolkit.Wit
{
    /// <summary>
    /// Translator for the change list
    /// </summary>
    class TfsChangeListTranslator: IEnumerable<IWorkItemUpdate>
    {
        private TfsWorkItemUpdatePackage m_changeList;         // Original change list

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="changeList">Change list that should be translated</param>
        public TfsChangeListTranslator(
            TfsWorkItemUpdatePackage changeList)
        {
            m_changeList = changeList;
        }

        #region IEnumerable<IWorkItemUpdate> Members

        public IEnumerator<IWorkItemUpdate> GetEnumerator()
        {
            return new TfsUpdateEnumerator(m_changeList);
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new TfsUpdateEnumerator(m_changeList);
        }

        #endregion
    }

    /// <summary>
    /// Enumerator for the TFS change list.
    /// </summary>
    class TfsUpdateEnumerator : IEnumerator<IWorkItemUpdate>
    {
        private TfsWorkItemUpdatePackage m_changeList;         // Original change list
        private int m_revision;                             // Current revision
        private int m_file;                                 // Current file
        private int m_link;                                 // Current link

        private int m_maxFiles;                             // Max number of attachments per revision
        private int m_maxLinks;                             // Max number of links per revision

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="changeList">Original change list</param>
        public TfsUpdateEnumerator(
            TfsWorkItemUpdatePackage changeList)
        {
            m_changeList = changeList;
            m_revision = -1;

            m_maxFiles = changeList.Core.Config.FileAttachmentConfig.AttachmentsPerUpdate;
            m_maxLinks = changeList.Core.Config.LinkConfig.LinksPerUpdate;

            m_file = -m_maxFiles;
            m_link = -m_maxLinks;
        }

        #region IEnumerator<IWorkItemUpdate> Members

        public IWorkItemUpdate Current
        {
            get
            {
                return GetCurrent();
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            // This method does nothing
        }

        #endregion

        #region IEnumerator Members

        object System.Collections.IEnumerator.Current
        {
            get
            {
                return GetCurrent();
            }
        }

        public bool MoveNext()
        {
            m_file += m_maxFiles;
            m_link += m_maxLinks;

            if (++m_revision < m_changeList.Revisions.Count)
            {
                return true;
            }
            else
            {
                return m_file < m_changeList.FileAttachmentOperations.Count ||
                    m_link < m_changeList.LinkOperations.Count;
            }
        }

        public void Reset()
        {
            m_revision = -1;
            m_file = -m_maxFiles;
            m_link = -m_maxLinks;
        }

        #endregion

        /// <summary>
        /// Creates and returns update statement at the current position.
        /// </summary>
        /// <returns>Statement at the current position</returns>
        private IWorkItemUpdate GetCurrent()
        {
            MigrationRevision rev;

            if (m_revision >= m_changeList.Revisions.Count)
            {
                // Create new revision
                rev = new MigrationRevision(m_changeList.SourceId, m_changeList.Core.UserName);
            }
            else
            {
                // Get existing revision
                rev = m_changeList.Revisions[m_revision];
            }

            bool isNew = m_revision == 0 && m_changeList.Target == null;
            TfsWorkItemUpdate u = isNew ?
                TfsWorkItemUpdate.CreateInsert(m_changeList, rev) : TfsWorkItemUpdate.CreateUpdate(
                m_changeList, rev);

            if (m_file < m_changeList.FileAttachmentOperations.Count)
            {
                int count = Math.Min(m_maxFiles, m_changeList.FileAttachmentOperations.Count - m_file);

                for (int i = m_file; i < m_file + count; i++)
                {
                    u.AddFile(m_changeList.ClientService, m_changeList.FileAttachmentOperations[i]);
                }
            }

            if (m_link < m_changeList.LinkOperations.Count)
            {
                int count = Math.Min(m_maxLinks, m_changeList.LinkOperations.Count - m_link);

                for (int i = m_link; i < m_link + count; i++)
                {
                    SyncActionContainer<ILink> op = m_changeList.LinkOperations[i];

                    op.Item.UpdateTfs(op.Action, u);
                }
            }
            return u;
        }
    }
}
